package cn.keniykey.mc.landterritory.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;

import cn.keniykey.mc.landterritory.LandTerritoryMain;
import cn.keniykey.mc.landterritory.toolkit.DebugUtil;

public final class MySQLCore extends AbDataBase{
	private Connection con;
	private final String baseurl,basetype;
	private final Properties baseinfo;
	private volatile Thread thread;
	private volatile LinkedList<DataRepository> links;
	//
	MySQLCore(String host,int port,String sqlname,String user,String password) throws ClassNotFoundException{
		Class.forName("com.mysql.jdbc.Driver"); //8.0版本下的MySQL
		this.baseurl = "jdbc:mysql://" + host + ":" + port + "/" + sqlname;
		this.baseinfo = new Properties();
		this.baseinfo.setProperty("user", user);
		this.baseinfo.setProperty("password", password);
		this.baseinfo.setProperty("useUnicode", "true");
		this.baseinfo.setProperty("characterEncoding", "utf8");
		this.baseinfo.setProperty("autoReconnect", "true");
		this.basetype = "MySQL";
		this.links = new LinkedList<>();
	}
	MySQLCore(String host,int port,String sqlname,String user,String password,boolean useSSL,String timezone) throws ClassNotFoundException {
		try{
			Class.forName("com.mysql.cj.jdbc.Driver"); //8.0及以上MYSQL版本
		}catch(Exception ex) {
			try{
				Class.forName("com.mysql.jdbc.Driver");
			}catch(Exception exx) {
				throw new ClassNotFoundException("找不到数据库驱动", ex);
			}
		}
		this.baseurl = "jdbc:mysql://" + host + ":" + port + "/" + sqlname;
		this.baseinfo = new Properties();
		this.baseinfo.setProperty("user", user);
		this.baseinfo.setProperty("password", password);
		this.baseinfo.setProperty("useUnicode", "true");
		this.baseinfo.setProperty("characterEncoding", "utf8");
		this.baseinfo.setProperty("autoReconnect", "true");
		this.baseinfo.setProperty("useSSL", useSSL ? "true" : "false");
		this.baseinfo.setProperty("serverTimezone", timezone);
		this.basetype = "MySQL8.0";
		this.links = new LinkedList<>();
	}
	//
	@Override
	public Connection getConnection() {
		try {
			if(this.con != null && !this.con.isClosed() && this.con.isValid(5)) return this.con;
		}catch(SQLException ex) {
			LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]判断数据库连接报错");
			ex.printStackTrace();
		}
		try {
			return this.con = DriverManager.getConnection(this.baseurl,this.baseinfo);
		}catch(SQLException ex) {
			LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]获取数据库连接报错");
			ex.printStackTrace();
		}
		return null;
	}
	@Override
	public void update(String sql, Object... objs) {
		synchronized (this.links) {
			this.links.add(new DataRepository(sql, objs));
		}
		DebugUtil.info("[MySQLCore]数据队列中已加入新数据");
		if (this.thread == null || !this.thread.isAlive()) {
			this.thread = new DataBaseThread();
			this.thread.start();
		}
	}
	private final class DataBaseThread extends Thread {
		DataBaseThread() {}
		public void run() {
			try {
				DebugUtil.info("[MySQLCore]数据队列清空线程启动");
				Thread.sleep(3000L);
			} catch (Exception ex) {
				LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]无法完成线程休眠延时等待");
				ex.printStackTrace();
			}
			MySQLCore.this.fush();
		}
	}
	@Override
	public synchronized void fush() {
		DebugUtil.info("[MySQLCore]数据队列开始清空");
		while(!this.links.isEmpty()) {
			final DataRepository dr;
			synchronized (this.links) {
				dr = this.links.removeFirst();
			}
			try{
				this.excute(dr.getSQL(), dr.getValues());
			}catch(Exception ex) {
				LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]数据库fush无法执行指令：" + dr.toString());
				ex.printStackTrace();
			}
		}
		DebugUtil.info("[MySQLCore]数据队列清空结束");
	}
	@Override
	public void excute(String sql, Object... objs) throws SQLException {
		final PreparedStatement ps;
		try {
			ps = this.getConnection().prepareStatement(sql);
		}catch(Exception ex) {
			LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]数据库无法获取PrepareStatement：" + sql);
			ex.printStackTrace();
			return;
		}
		try {
			if(objs != null && objs.length > 0) AbDataBase.setParameters(ps, objs);
			ps.execute();
		}finally {
			try{
				ps.close();
			}catch(Exception ex) {
				LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]数据库无法关闭PrepareStatement");
				DebugUtil.info(ex);;
			}
		}
	}
	@Override
	public ResultSet query(String sql, Object... objs) throws SQLException {
		final PreparedStatement ps = this.getConnection().prepareStatement(sql);
		if(objs != null && objs.length > 0) AbDataBase.setParameters(ps, objs);
		return ps.executeQuery();
	}
	@Override
	protected void close() {
		try {
			if (this.con != null && !this.con.isClosed()) {
				this.fush();
				DebugUtil.info("[MySQLCore]数据库已完成等待数据队列净空");
				this.con.close();
				DebugUtil.info("[MySQLCore]数据库关闭成功");
				this.con = null;
			}
		} catch (SQLException ex) {
			LandTerritoryMain.getPlugin().getLogger().warning("[MySQLCore]数据库关闭异常");
			ex.printStackTrace();
		}
	}
	@Override
	public String toString() {
		return this.basetype;
	}
}